package com.cn.algorithm02.class15;

import java.util.PriorityQueue;

/***
 * @author: hels
 * @description: 哈夫曼编码问题：一条金条切割两半，是需要花费和长度一样的铜板，求怎么花费的铜板最少？
 * 例如给长度为60的金条，切割{10,20,30}
 * 第一次切割10,50，花费60铜板；第二次将50切割20,30，花费50铜板，共计110铜板；
 * 第一次切割30,30，花费60铜板；第二次将30切割20,10，花费30铜板，共计90铜板；
 * 顺序不论
 **/
public class C02_LessMoneySplitGold {
    public static void main(String[] args) {
        int[] arr = generateArray(20, 8);
        System.out.println("贪心算法结果：");
        System.out.println(lessMoneySplitGold(arr));
        System.out.println("暴力破解法：");
        System.out.println(lessMoneySplitGold2(arr));
    }

    // 贪心算法（利用哈夫曼编码）
    public static int lessMoneySplitGold(int[] arr) {
        if (arr == null) return 0;

        // 将数据放入小根堆
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        for (int i : arr) {
            queue.add(i);
        }

        int ans = 0;
        int reslut = 0;
        while (queue.size() > 1) {
            reslut = queue.poll() + queue.poll();
            ans += reslut;
            queue.add(reslut);
        }

        return ans;
    }

    // 暴力破解：
    public static int lessMoneySplitGold2(int[] arr) {
        if (arr == null) return 0;

        return process(arr, 0);
    }

    /**
     * for test
     *
     * @param arr 合并后的数组
     * @param pre 合并时产生的代价
     * @return 返回最小的代价
     */
    public static int process(int[] arr, int pre) {
        if (arr.length == 1) return pre;

        int ans = Integer.MAX_VALUE;
        for (int i = 0; i < arr.length; i++) {
            for (int j = i + 1; j < arr.length; j++) {
                // 本次任意两个切割的代价
                ans = Math.min(ans, process(copyAndExcept(arr, i, j), pre + arr[i] + arr[j]));
            }
        }

        return ans;
    }

    //  for test
    private static int[] copyAndExcept(int[] arr, int i, int j) {
        int[] ans = new int[arr.length - 1];
        int index = 0;
        for (int k = 0; k < arr.length; k++) {
            if (k != i && k != j) {
                ans[index++] = arr[k];
            }
        }
        ans[ans.length - 1] = arr[i] + arr[j];
        return ans;
    }

    /**
     * 生成随机数组
     */
    public static int[] generateArray(int maxValue, int maxSize) {
        int size = (int) (Math.random() * maxSize + 2);
        int[] ans = new int[size];
//        System.out.println(ans.length);
//        System.out.println("数组元素有：" );
        for (int i = 0; i < ans.length; i++) {
            ans[i] = (int) (Math.random() * maxValue);
//            System.out.println(ans[i]);
        }
//        System.out.println("======");
        return ans;
    }

}
